/*
 * Parser2.cpp
 *
 *  Created on: Nov 6, 2010
 *      Author: dhovemey
 */

#include <memory>
#include <cassert>
#include "util/String.h"
#include "util/Error.h"
#include "fe/Lexer2.h"
#include "fe/Token2.h"
#include "fe/ASTNode.h"
#include "fe/ParserException.h"
#include "fe/Parser2.h"

// ----------------------------------------------------------------------
// We're not using exception handling,
// so we use the following macros to allow abrupt returns
// from parse functions on the detection of an error
// (lexical or syntax).
// ----------------------------------------------------------------------

#define UNEXPECTED_TOKEN(tok) \
	do { \
		Error::raise(new ParserException(L"Unexpected token `" + (tok)->getLexeme() + L"'", (tok)->getLocation())); \
		return 0; \
	} while (0)

#define PEEK(tokVar) \
	do { \
		if (!m_lexer->next(tokVar)) { \
			return 0; \
		} \
	} while (0)

#define PEEK_NEXT(tokVar) \
	do { \
		PEEK(tokVar); \
		if ((tokVar) == 0) { \
			Error::raise(new ParserException(L"Unexpected end of input", m_lexer->getCurrentLocation())); \
			return 0; \
		} \
	} while (0)

#define EXPECT(tokVar, tokenType) \
	do { \
		Token2::TokenType tType_ = (tokenType); \
		PEEK_NEXT(tokVar); \
		if ((tokVar)->getTokenType() != tType_) { \
			UNEXPECTED_TOKEN(tokVar); \
		} \
		m_lexer->consume(); \
	} while (0)

#define EXPECT_IGNORE(tokenType) \
	do { \
		Token2 *tok_; \
		EXPECT(tok_, tokenType); \
	} while (0)

#define ADD_CHILD(parent, child) \
	do { \
		ASTNode *child_ = (child); \
		if ((child_) == 0) { \
			return 0; \
		} \
		(parent)->appendChild(child_); \
	} while (0)

// ----------------------------------------------------------------------
// Methods
// ----------------------------------------------------------------------

Parser2::Parser2(Lexer2 *lexerToAdopt)
	: m_lexer(lexerToAdopt)
{

}

Parser2::~Parser2()
{
	delete m_lexer;
}

ASTNode *Parser2::parseTranslationUnit()
{
	typedef std::vector<ASTNode *> TopLevelItemList;

	TopLevelItemList topLevelItemList;
	bool err = false;

	Token2 *next;
	PEEK_NEXT(next);

	// parse imports (if any)
	if (next->getTokenType() == Token2::IMPORT) {
		ASTNode *importList = parseImportList();
		if (!importList) {
			err = true;
		}
	}

	// parse top level items
	if (!err) {
		for (;;) {
			PEEK(next);
			if (next == 0) {
				break;
			}
			ASTNode *topLevelItem = parseTopLevelItem();
			if (!topLevelItem) {
				err = true;
				break;
			}
			topLevelItemList.push_back(topLevelItem);
		}
	}

	if (err) {
		// clean up
		for (TopLevelItemList::iterator i = topLevelItemList.begin(); i != topLevelItemList.end(); i++) {
			delete *i;
		}
		return 0;
	}

	// We have all of the top level items now.
	// Re-arrange them into a single unit node.
	// In particular, any top-level statements need to go into
	// the main$ method of a Main$ class.
	ASTNode *unit = new ASTNode(ASTNode::AST_UNIT, m_lexer->getCurrentLocation());
	ASTNode *mainClass = 0;
	ASTNode *mainMethod = 0;

	for (TopLevelItemList::iterator i = topLevelItemList.begin(); i != topLevelItemList.end(); i++) {
		ASTNode *tli = *i;
		if (tli->getType() == ASTNode::AST_CLASS || tli->getType() == ASTNode::AST_MODULE) {
			unit->appendChild(tli);
		} else {
			if (!mainMethod) {
				mainClass = new ASTNode(ASTNode::AST_CLASS, tli->getLocation());
				mainClass->setStringValue(L"Main$");

				mainMethod = new ASTNode(ASTNode::AST_METHOD, tli->getLocation());
				mainMethod->setStringValue(L"main$");
				mainMethod->appendChild(new ASTNode(ASTNode::AST_VAR_LIST, tli->getLocation())); // empty param list
				mainMethod->appendChild(new ASTNode(ASTNode::AST_STATEMENT_LIST, tli->getLocation()));

				mainClass->appendChild(mainMethod);
			}
			mainMethod->getChildList().at(1)->appendChild(*i); // append to statement list
		}
	}
	if (mainClass) {
		unit->appendChild(mainClass);
	}
	return unit;
}

ASTNode *Parser2::parseTopLevelItem()
{
	Token2 *next;
	PEEK_NEXT(next);
	if (next->getTokenType() == Token2::CLASS || next->getTokenType() == Token2::MODULE) {
		return parseClassOrModule();
	} else {
		return parseStatement();
	}
}

ASTNode *Parser2::parseImportList()
{
	std::unique_ptr<ASTNode> importList(new ASTNode(ASTNode::AST_IMPORT_LIST, m_lexer->getCurrentLocation()));

	Token2 *next;

	for (;;) {
		PEEK(next);
		if (next == 0 || next->getTokenType() != Token2::IMPORT) {
			break;
		}
		ADD_CHILD(importList, parseImport());
	}

	return importList.release();
}

ASTNode *Parser2::parseImport()
{
	Token2 *next;
	EXPECT(next, Token2::IMPORT);
	std::unique_ptr<ASTNode> importAST(new ASTNode(ASTNode::AST_IMPORT, next->getLocation()));

	std::wstring clsName;
	if (!scanQualifiedClassName(clsName)) {
		return 0;
	}

	std::unique_ptr<Import> import;

	// Check to see if this is
	//   a class import using an AS clause to establish an explicit alias
	//   a static method import from a module
	PEEK_NEXT(next);
	if (next->getTokenType() == Token2::AS) {
		EXPECT_IGNORE(Token2::AS);
		EXPECT(next, Token2::IDENT);
		import.reset(new Import(clsName, next->getLexeme())); // class import with explicit alias
	} else if (next->getTokenType() == Token2::METHOD) {
		EXPECT_IGNORE(Token2::METHOD);
		EXPECT(next, Token2::IDENT);
		import.reset(new Import(clsName, next->getLexeme(), true)); // static method import
	} else {
		import.reset(new Import(clsName)); // normal class import with implicit alias
	}
	EXPECT_IGNORE(Token2::SEMICOLON);

	importAST->adoptImport(import.release());

	return importAST.release();
}

int Parser2::scanQualifiedClassName(std::wstring &clsName)
{
	Token2 *ident;
	EXPECT(ident, Token2::IDENT);
	clsName += ident->getLexeme();
	for (;;) {
		Token2 *next;
		PEEK(next);
		if (next == 0 || next->getTokenType() != Token2::DOUBLECOLON) {
			break;
		}
		clsName += next->getLexeme();
		m_lexer->consume();
		EXPECT(ident, Token2::IDENT);
		clsName += ident->getLexeme();
	}
	return 1;
}

ASTNode *Parser2::parseStatementList()
{
	Token2 *next;
	PEEK_NEXT(next);
	std::unique_ptr<ASTNode> stmtList(new ASTNode(ASTNode::AST_STATEMENT_LIST, next->getLocation()));

	do {
		ADD_CHILD(stmtList, parseStatement());
		PEEK(next);
	} while (next != 0 && next->getTokenType() != Token2::RBRACE);

	return stmtList.release();
}

ASTNode *Parser2::parseStatement()
{
	Token2 *next;
	PEEK_NEXT(next);
	switch (next->getTokenType()) {
	case Token2::VAR:
		return parseVariableDeclaration();
	case Token2::CLASS:
	case Token2::MODULE:
		// These are not statements - they should only appear as top level items
		Error::raise(new ParserException(L"Class/module is only allowed at top level", next->getLocation()));
		return 0;
	case Token2::WHILE:
		return parseWhileStatement();
	case Token2::IF:
		return parseIfStatement();
	case Token2::RETURN:
		return parseReturnStatement();
	default:
		return parseExpressionStatement();
	}
}

ASTNode *Parser2::parseVariableDeclaration()
{
	Token2 *next;
	EXPECT(next, Token2::VAR);
	std::unique_ptr<ASTNode> ast(parseVarWithOptInitList());
	if (ast.get() == 0) {
		return 0;
	}
	ast->setLocation(next->getLocation());
	EXPECT_IGNORE(Token2::SEMICOLON);
	return ast.release();
}

ASTNode *Parser2::parseVarWithOptInitList()
{
	std::unique_ptr<ASTNode> varList(new ASTNode(ASTNode::AST_VAR_LIST, m_lexer->getCurrentLocation()));

	Token2 *next;
	for (;;) {
		ADD_CHILD(varList, parseVarWithOptInit());
		PEEK(next);
		if (next == 0 || next->getTokenType() != Token2::COMMA) {
			break;
		}
		m_lexer->consume();
	}

	return varList.release();
}

ASTNode *Parser2::parseVarWithOptInit()
{
	Token2 *next;
	EXPECT(next, Token2::IDENT);
	std::unique_ptr<ASTNode> varWithOptInit(new ASTNode(ASTNode::AST_VAR, next->getLocation()));
	varWithOptInit->setStringValueFromToken(next);
	PEEK(next);
	if (next != 0 && next->getTokenType() == Token2::ASSIGN) {
		m_lexer->consume();
		ADD_CHILD(varWithOptInit, parseExpression());
	}
	return varWithOptInit.release();
}

ASTNode *Parser2::parseClassOrModule()
{
	Token2 *next;
	PEEK_NEXT(next);
	assert(next->getTokenType() == Token2::CLASS || next->getTokenType() == Token2::MODULE);

	std::unique_ptr<ASTNode> clsOrModule(new ASTNode(next->getTokenType() == Token2::CLASS ? ASTNode::AST_CLASS : ASTNode::AST_MODULE, next->getLocation()));
	m_lexer->consume();

	std::wstring clsName;
	if (!scanQualifiedClassName(clsName)) {
		return 0;
	}
	clsOrModule->setStringValue(clsName);

	EXPECT_IGNORE(Token2::LBRACE);
	ADD_CHILD(clsOrModule, parseOptMemberList());
	EXPECT_IGNORE(Token2::RBRACE);

	return clsOrModule.release();
}

ASTNode *Parser2::parseOptMemberList()
{
	std::unique_ptr<ASTNode> memberList(new ASTNode(ASTNode::AST_MEMBER_LIST, m_lexer->getCurrentLocation()));
	Token2 *next;
	PEEK(next);
	while (next != 0 && next->getTokenType() != Token2::RBRACE) {
		ADD_CHILD(memberList, parseMember());
		PEEK(next);
	}
	return memberList.release();
}

ASTNode *Parser2::parseMember()
{
	Token2 *next;
	PEEK_NEXT(next);
	if (next->getTokenType() == Token2::FIELD) {
		return parseField();
	} else if (next->getTokenType() == Token2::METHOD) {
		return parseMethod();
	} else if (next->getTokenType() == Token2::MAGIC) {
		return parseMagicMethod();
	} else {
		Error::raise(new ParserException(L"Expected field or method", next->getLocation()));
		return 0;
	}
}

ASTNode *Parser2::parseField()
{
	Token2 *next;
	EXPECT(next, Token2::FIELD);
	std::unique_ptr<ASTNode> field(new ASTNode(ASTNode::AST_FIELD, next->getLocation()));
	EXPECT(next, Token2::IDENT);
	field->setStringValueFromToken(next);
	EXPECT_IGNORE(Token2::SEMICOLON);
	return field.release();
}

bool Parser2::checkLegalMethodName(Token2 *token)
{
	Token2::TokenType tt = token->getTokenType();
	if (tt == Token2::IDENT || (tt >= Token2::TOK_FIRST_BIN_OP && tt <= Token2::TOK_LAST_BIN_OP)) {
		return true;
	} else {
		Error::raise(new ParserException(L"Expected identifier or binary operator", token->getLocation()));
		return false;
	}
}

ASTNode *Parser2::parseMethod()
{
	Token2 *next;
	EXPECT(next, Token2::METHOD);
	std::unique_ptr<ASTNode> method(new ASTNode(ASTNode::AST_METHOD, next->getLocation()));
	PEEK_NEXT(next);
	if (checkLegalMethodName(next)) {
		method->setStringValueFromToken(next);
		m_lexer->consume();
	} else {
		return 0;
	}
	EXPECT_IGNORE(Token2::LPAREN);
	ADD_CHILD(method, parseOptParamList());
	EXPECT_IGNORE(Token2::RPAREN);
	EXPECT_IGNORE(Token2::LBRACE);
	ADD_CHILD(method, parseOptStatementList());
	EXPECT_IGNORE(Token2::RBRACE);

	return method.release();
}

ASTNode *Parser2::parseOptParamList()
{
	std::unique_ptr<ASTNode> paramList(new ASTNode(ASTNode::AST_VAR_LIST, m_lexer->getCurrentLocation()));
	Token2 *next;
	PEEK_NEXT(next);
	if (next != 0 && next->getTokenType() != Token2::RPAREN) {
		for (;;) {
			EXPECT(next, Token2::IDENT);
			ASTNode *var = new ASTNode(ASTNode::AST_VAR, next->getLocation());
			var->setStringValueFromToken(next);
			ADD_CHILD(paramList, var);
			PEEK_NEXT(next);
			if (next->getTokenType() != Token2::COMMA) {
				// end of param list
				break;
			}
			m_lexer->consume();
		}
	}
	return paramList.release();
}

ASTNode *Parser2::parseOptStatementList()
{
	std::unique_ptr<ASTNode> stmtList(new ASTNode(ASTNode::AST_STATEMENT_LIST, m_lexer->getCurrentLocation()));
	Token2 *next;
	PEEK(next);
	while (next != 0 && next->getTokenType() != Token2::RBRACE) {
		ADD_CHILD(stmtList, parseStatement());
		PEEK(next);
	}
	return stmtList.release();
}

ASTNode *Parser2::parseMagicMethod()
{
	Token2 *next;
	EXPECT(next, Token2::MAGIC);
	std::unique_ptr<ASTNode> magicMethod(new ASTNode(ASTNode::AST_MAGIC_METHOD, next->getLocation()));
	EXPECT_IGNORE(Token2::METHOD);
	PEEK_NEXT(next);
	if (checkLegalMethodName(next)) {
		magicMethod->setStringValueFromToken(next);
		m_lexer->consume();
	} else {
		return 0;
	}
	EXPECT_IGNORE(Token2::LPAREN);
	ADD_CHILD(magicMethod, parseOptParamList());
	EXPECT_IGNORE(Token2::RPAREN);
	EXPECT_IGNORE(Token2::SEMICOLON);
	return magicMethod.release();
}

ASTNode *Parser2::parseWhileStatement()
{
	Token2 *next;
	EXPECT(next, Token2::WHILE);
	std::unique_ptr<ASTNode> whileStmt(new ASTNode(ASTNode::AST_WHILE_STATEMENT, next->getLocation()));
	EXPECT_IGNORE(Token2::LPAREN);
	ADD_CHILD(whileStmt, parseExpression());
	EXPECT_IGNORE(Token2::RPAREN);
	EXPECT_IGNORE(Token2::LBRACE);
	ADD_CHILD(whileStmt, parseOptStatementList());
	EXPECT_IGNORE(Token2::RBRACE);
	return whileStmt.release();
}

ASTNode *Parser2::parseIfStatement()
{
	Token2 *next;
	EXPECT(next, Token2::IF);
	std::unique_ptr<ASTNode> ifStmt(new ASTNode(ASTNode::AST_IF_STATEMENT, next->getLocation()));
	EXPECT_IGNORE(Token2::LPAREN);
	ADD_CHILD(ifStmt, parseExpression());
	EXPECT_IGNORE(Token2::RPAREN);
	EXPECT_IGNORE(Token2::LBRACE);
	ADD_CHILD(ifStmt, parseOptStatementList());
	EXPECT_IGNORE(Token2::RBRACE);
	PEEK(next);
	if (next != 0 && next->getTokenType() == Token2::ELSE) {
		m_lexer->consume();
		EXPECT_IGNORE(Token2::LBRACE);
		ADD_CHILD(ifStmt, parseOptStatementList());
		EXPECT_IGNORE(Token2::RBRACE);
	}
	return ifStmt.release();
}

ASTNode *Parser2::parseReturnStatement()
{
	Token2 *next;
	EXPECT(next, Token2::RETURN);
	std::unique_ptr<ASTNode> retStmt(new ASTNode(ASTNode::AST_RETURN_STATEMENT, next->getLocation()));
	ADD_CHILD(retStmt, parseExpression());
	EXPECT_IGNORE(Token2::SEMICOLON);
	return retStmt.release();
}

ASTNode *Parser2::parseExpressionStatement()
{
	Token2 *next;
	PEEK_NEXT(next);
	std::unique_ptr<ASTNode> exprStmt(new ASTNode(ASTNode::AST_STATEMENT, next->getLocation()));
	ADD_CHILD(exprStmt, parseExpression());
	EXPECT_IGNORE(Token2::SEMICOLON);
	return exprStmt.release();
}

// Operator precedence parser for expressions:
// see http://en.wikipedia.org/wiki/Operator-precedence_parser

ASTNode *Parser2::parseExpression()
{
	return parseExpressionWithPrec(parsePrimary(), 0);
}

ASTNode *Parser2::parseExpressionWithPrec(ASTNode *lhs_, int minPrec)
{
	std::unique_ptr<ASTNode> lhs(lhs_);
	Token2 *next;

	// while the next token is a binary operator whose precedence is >= min_precedence
	for (;;) {
		PEEK_NEXT(next);
		Token2::TokenType op = next->getTokenType();
		if ( !(Token2::isBinOpOrAssign(op) && Token2::getPrecedence(op) >= minPrec) ) {
			break;
		}
		m_lexer->consume();
		int opPrec = Token2::getPrecedence(op);
		std::unique_ptr<ASTNode> rhs(parsePrimary());
		if (rhs.get() == 0) {
			return 0;
		}
		// while the next token is a binary operator whose precedence is greater
		// than op's, or a right-associative operator
		// whose precedence is equal to op's
		for (;;) {
			PEEK_NEXT(next);
			Token2::TokenType lookahead = next->getTokenType();
			if (! Token2::isBinOpOrAssign(lookahead)) {
				break;
			}
			int lookaheadPrec = Token2::getPrecedence(lookahead);
			if ( !((Token2::isLeftAssoc(lookahead) && lookaheadPrec > opPrec) ||
					(Token2::isRightAssoc(lookahead) && lookaheadPrec == opPrec) ) ) {
				break;
			}
			rhs.reset(parseExpressionWithPrec(rhs.release(), lookaheadPrec));
			if (rhs.get() == 0) {
				return 0;
			}
		}
		ASTNode *combine = new ASTNode(ASTNode::AST_BINARY_OP_EXPR, lhs->getLocation());
		combine->appendChild(lhs.release());
		combine->appendChild(rhs.release());
		combine->setIntValue(op);
		lhs.reset(combine);
	}
	return lhs.release();
}

ASTNode *Parser2::parsePrimary()
{
	Token2 *next;
	PEEK_NEXT(next);
	if (next->getTokenType() == Token2::NOT) {
		// logical not expression
		std::unique_ptr<ASTNode> notExpr(new ASTNode(ASTNode::AST_UNARY_OP_EXPRESSION, next->getLocation()));
		ADD_CHILD(notExpr, parsePrimary());
		return notExpr.release();
	} else if (next->getTokenType() == Token2::LPAREN) {
		// explicitly parenthesized expression
		EXPECT_IGNORE(Token2::LPAREN);
		std::unique_ptr<ASTNode> expr(parseExpression());
		if (expr.get() == 0) {
			return 0;
		}
		EXPECT_IGNORE(Token2::RPAREN);
		return expr.release();
	} else {
		// Start with a "leaf" expression
		std::unique_ptr<ASTNode> primary(parseLeaf());
		if (primary.get() == 0) {
			return 0;
		}

		// Resolve any chain of field accesses and/or method calls that may be
		// tacked onto the leaf.
		for (;;) {
			PEEK_NEXT(next);
			if (next->getTokenType() != Token2::DOT) {
				// done with primary
				break;
			}
			// Field access or method call!
			m_lexer->consume();
			PEEK_NEXT(next);
			if (next->getTokenType() == Token2::IDENT) {
				// field access or identifier-named method call
				std::wstring memberName(next->getLexeme());
				m_lexer->consume();
				PEEK_NEXT(next);
				if (next->getTokenType() == Token2::LPAREN) {
					// method call
					std::unique_ptr<ASTNode> methodCall(new ASTNode(ASTNode::AST_METHOD_CALL_EXPR, primary->getLocation()));
					if (!completeMethodCall(primary, methodCall, memberName)) {
						return 0;
					}
				} else {
					// assume field access
					ASTNode *fieldAccess = new ASTNode(ASTNode::AST_FIELD_REF_EXPR, primary->getLocation());
					fieldAccess->setStringValue(memberName);
					fieldAccess->appendChild(primary.release());
					primary.reset(fieldAccess);
				}
			} else if (Token2::isBinOp(next->getTokenType())) {
				// method call, but with a binary operator as the method name
				std::wstring opName(next->getLexeme());
				m_lexer->consume();
				std::unique_ptr<ASTNode> methodCall(new ASTNode(ASTNode::AST_METHOD_CALL_EXPR, primary->getLocation()));
				if (!completeMethodCall(primary, methodCall, opName)) {
					return 0;
				}
			} else {
				UNEXPECTED_TOKEN(next);
			}
		}
		return primary.release();
	}
}

int Parser2::completeMethodCall(
		std::unique_ptr<ASTNode> &primary, std::unique_ptr<ASTNode> &methodCall, const std::wstring &methodName)
{
	methodCall->setStringValue(methodName);     // name of called method
	ADD_CHILD(methodCall, primary.release());   // first child is expression computing receiver ref
	EXPECT_IGNORE(Token2::LPAREN);
	ADD_CHILD(methodCall, parseArgumentList()); // second child is argument list
	EXPECT_IGNORE(Token2::RPAREN);
	primary.reset(methodCall.release());
	return 1;
}

ASTNode *Parser2::parseLeaf()
{
	Token2 *next;
	PEEK_NEXT(next);
	Token2::TokenType tt = next->getTokenType();
	switch (tt) {
	case Token2::SELF:
		{
			m_lexer->consume();
			return new ASTNode(ASTNode::AST_SELF_REF_EXPR, next->getLocation());
		}
	case Token2::SYMBOL_LITERAL:
		{
			ASTNode *symLitExpr = new ASTNode(ASTNode::AST_SYMBOL_LITERAL_EXPR, next->getLocation());
			symLitExpr->setStringValueFromToken(next);
			m_lexer->consume();
			return symLitExpr;
		}
	case Token2::COLON:
		{
			std::unique_ptr<ASTNode> symLitExpr(new ASTNode(ASTNode::AST_SYMBOL_LITERAL_EXPR, next->getLocation()));
			m_lexer->consume();
			PEEK_NEXT(next);
			if (next->getTokenType() == Token2::IDENT) {
				// a symbol literal of the form
				//     : name
				symLitExpr->setStringValueFromToken(next);
				m_lexer->consume();
			} else if (next->getTokenType() == Token2::STRING_LITERAL) {
				// a symbol literal of the form
				//    : "name"
				if (!symLitExpr->setStringValueFromStringLiteral(next)) {
					return 0;
				}
				m_lexer->consume();
			} else {
				UNEXPECTED_TOKEN(next);
			}
			return symLitExpr.release();
		}
	case Token2::STRING_LITERAL:
		{
			std::unique_ptr<ASTNode> strLitExpr(new ASTNode(ASTNode::AST_STRING_LITERAL_EXPR, next->getLocation()));
			if (!strLitExpr->setStringValueFromStringLiteral(next)) {
				return 0;
			}
			m_lexer->consume();
			return strLitExpr.release();
		}
	case Token2::INT_LITERAL:
		{
			ASTNode *intLitExpr = new ASTNode(ASTNode::AST_INT_LITERAL_EXPR, next->getLocation());
			intLitExpr->setIntValue(String::wsToInt(next->getLexeme().c_str()));
			m_lexer->consume();
			return intLitExpr;
		}
	case Token2::TRUE:
	case Token2::FALSE:
		{
			ASTNode *boolLitExpr = new ASTNode(ASTNode::AST_BOOLEAN_LITERAL_EXPR, next->getLocation());
			boolLitExpr->setIntValue(tt == Token2::TRUE ? 1 : 0);
			m_lexer->consume();
			return boolLitExpr;
		}
	case Token2::IDENT:
		{
			// this could be either a plain variable reference, or a call to a method
			// imported statically from a module
			std::wstring name(next->getLexeme());
			Location loc(next->getLocation());
			m_lexer->consume();
			PEEK_NEXT(next);
			if (next->getTokenType() == Token2::LPAREN) {
				// static call
				std::unique_ptr<ASTNode> staticCallExpr(new ASTNode(ASTNode::AST_MODULE_METHOD_CALL_EXPR, loc));
				staticCallExpr->setStringValue(name);
				EXPECT_IGNORE(Token2::LPAREN);
				ADD_CHILD(staticCallExpr, parseArgumentList());
				EXPECT_IGNORE(Token2::RPAREN);
				return staticCallExpr.release();

			} else {
				// variable reference
				ASTNode *varRefExpr = new ASTNode(ASTNode::AST_VAR_REF_EXPR, loc);
				varRefExpr->setStringValue(name);
				return varRefExpr;
			}
		}
	case Token2::NEW:
		{
			std::unique_ptr<ASTNode> newExpr(new ASTNode(ASTNode::AST_NEW_EXPR, next->getLocation()));
			m_lexer->consume();
			std::wstring clsName;
			if (!scanQualifiedClassName(clsName)) {
				return 0;
			}
			newExpr->setStringValue(clsName);
			EXPECT_IGNORE(Token2::LPAREN);
			ADD_CHILD(newExpr, parseArgumentList());
			EXPECT_IGNORE(Token2::RPAREN);
			return newExpr.release();
		}
	default:
		{
			UNEXPECTED_TOKEN(next);
		}
	}
}

ASTNode *Parser2::parseArgumentList()
{
	Token2 *next;
	PEEK_NEXT(next);
	std::unique_ptr<ASTNode> argList(new ASTNode(ASTNode::AST_ARG_LIST, next->getLocation()));
	if (next->getTokenType() != Token2::RPAREN) {
		for (;;) {
			ADD_CHILD(argList, parseExpression());
			PEEK_NEXT(next);
			if (next->getTokenType() == Token2::RPAREN) {
				break;
			} else if (next->getTokenType() == Token2::COMMA) {
				// argument list continues
				m_lexer->consume();
			} else {
				UNEXPECTED_TOKEN(next);
			}
		}
	}
	return argList.release();
}
